package br.com.harley.torneio.business;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;

import br.com.harley.torneio.constant.MensagemAplicacaoErro;
import br.com.harley.torneio.domain.StatusTorneio;
import br.com.harley.torneio.domain.Torneio;
import br.com.harley.torneio.exception.NegocioException;
import br.com.harley.torneio.persistence.TorneioDAO;
import br.com.harley.torneio.util.Constantes;
import br.com.harley.torneio.util.MensagemUtil;
import br.com.harley.torneio.validator.ValidadorGenerico;
import br.gov.frameworkdemoiselle.annotation.Name;
import br.gov.frameworkdemoiselle.message.Message;
import br.gov.frameworkdemoiselle.stereotype.BusinessController;
import br.gov.frameworkdemoiselle.template.DelegateCrud;
import br.gov.frameworkdemoiselle.transaction.Transactional;
import br.gov.frameworkdemoiselle.util.ResourceBundle;

@Name("torneioBC")
@BusinessController
public class ManterTorneioBC extends DelegateCrud<Torneio, Integer, TorneioDAO> implements IBaseBC {

	private static final long serialVersionUID = -7954068595238419428L;

	/**
	 * {@link Logger} da classe.
	 */
	@SuppressWarnings("unused")
	@Inject
	private Logger logger;

	@Inject
	private MensagemUtil mensagemUtil;

	@Inject
	private ResourceBundle bundle;

	@Inject
	private ValidadorGenerico validadorGenerico;

	@Transactional
	public void incluirTorneio(final Torneio novoTorneio) throws NegocioException {
		validarTorneio(novoTorneio);
		getDelegate().insert(novoTorneio);
	}

	public void abrirInscricoes(Torneio torneio, Date dtInicio, Date dtFim) throws NegocioException {
		validarDatas(dtInicio, dtFim);
		if (torneio.getStatus().equals(StatusTorneio.INCLUIDO)) {
			torneio.setDtInicioInscricoes(dtInicio);
			torneio.setDtFimInscricoes(dtFim);
			torneio.setStatus(StatusTorneio.INSCRICOES_ABERTAS);
			getDelegate().update(torneio);
		} else {
			List<Message> msgs = new ArrayList<Message>();
			msgs.add(mensagemUtil.buscaMensagem(MensagemAplicacaoErro.NAO_PODE_ABRIR_INSCRICOES));
			throw new NegocioException("Não foi possível abrir as inscrições para o torneio.", msgs);
		}
	}

	private void validarDatas(Date dtInicio, Date dtFim) throws NegocioException {
		List<Message> msgs = new ArrayList<Message>();
		if (!validadorGenerico.foiPreenchido(dtInicio)) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_OBRIGATORIO,
					bundle.getString(Constantes.LABELS.LABEL_DATA_INICIO_INSCRICOES));
			msgs.add(msg);
		}
		if (!validadorGenerico.foiPreenchido(dtFim)) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_OBRIGATORIO,
					bundle.getString(Constantes.LABELS.LABEL_DATA_FIM_INSCRICOES));
			msgs.add(msg);
		}
		if (msgs.isEmpty()) {
			if (!validadorGenerico.ehPeriodoValido(dtInicio, dtFim)) {
				Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.PERIODO_INVALIDO,
						bundle.getString(Constantes.LABELS.LABEL_PERIODO_DE_INSCRICOES));
				msgs.add(msg);
			}
		}
		if (!msgs.isEmpty()) {
			throw new NegocioException("Erro na validação das datas.", msgs);
		}
	}

	/**
	 * Atualiza um torneio existente.
	 * 
	 * @param torneio
	 *            Torneio sendo atualizado.
	 * @throws NegocioException
	 *             Caso haja erros na validação é lançada exceção de negócio com
	 *             sua lista de mensagens preenchida.
	 */
	@Transactional
	public void atualizarTorneio(final Torneio torneio) throws NegocioException {
		validarTorneio(torneio);
		getDelegate().update(torneio);
	}

	/**
	 * /** Método que verifica se já existe um torneio cadastrado com o nome
	 * informado.
	 * 
	 * @param jogador
	 *            Jogador cujo login está sendo verificado.
	 * @param listaDeTorneiosCadastrados
	 *            Lista de torneios cadastrados.
	 * @return True caso já exista torneio cadastrado com o nome informado e
	 *         False em caso contrário.
	 */
	private boolean existeOutroTorneioComMesmoNome(Torneio torneio, List<Torneio> listaDeTorneiosCadastrados) {
		for (Torneio torneioCadastrado : listaDeTorneiosCadastrados) {
			if (torneio.getNome() != null
					&& StringUtils.equalsIgnoreCase(torneioCadastrado.getNome().trim(), torneio.getNome().trim())) {
				if (torneio.getId() == null || !torneioCadastrado.getId().equals(torneio.getId())) {
					// retorna true apenas se existe torneio com mesmo nome na
					// lista e este torneio não é ele mesmo
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Realiza todas as validações necessárias para atualizar ou incluir um novo
	 * jogador.
	 * 
	 * @param torneio
	 *            Torneio sendo incluído ou atualizado.
	 * @return Lista contendo mensagens de erro de validação.
	 */
	private void validarTorneio(Torneio torneio) throws NegocioException {
		List<Message> msgs = new ArrayList<Message>();
		msgs.addAll(validarObrigatoriedadeDosCampos(torneio));
		msgs.addAll(validarFormacaoDosCampos(torneio));
		msgs.addAll(validarConsistenciaDosCampos(torneio));

		if (!msgs.isEmpty()) {
			throw new NegocioException("Erro na validação do torneio.", msgs);
		}
	}

	/**
	 * Valida o preenchimento dos campos obrigatórios.
	 * 
	 * @param torneio
	 *            Torneio sendo validado.
	 * @throws NegocioException
	 *             Caso haja erros na validação é lançada exceção de negócio com
	 *             sua lista de mensagens preenchida.
	 */
	private List<Message> validarObrigatoriedadeDosCampos(Torneio torneio) {
		List<Message> msgs = new ArrayList<Message>();
		if (!validadorGenerico.foiPreenchido(torneio.getNome())) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_OBRIGATORIO,
					bundle.getString(Constantes.LABELS.LABEL_NOME));
			msgs.add(msg);
		}
		return msgs;
	}

	/**
	 * Método que valida a consistência dos campos.
	 * 
	 * @param torneio
	 *            Jogador sendo validado.
	 * @throws NegocioException
	 *             Caso haja erros na validação é lançada exceção de negócio com
	 *             sua lista de mensagens preenchida.
	 */
	private List<Message> validarConsistenciaDosCampos(Torneio torneio) {
		List<Message> mensagens = new ArrayList<Message>();
		List<Torneio> listaDeTorneiosCadastrados = findAll();
		if (existeOutroTorneioComMesmoNome(torneio, listaDeTorneiosCadastrados)) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_UNICO_DUPLICADO,
					bundle.getString(Constantes.LABELS.LABEL_TORNEIO), bundle.getString(Constantes.LABELS.LABEL_NOME));
			mensagens.add(msg);
		}

		return mensagens;
	}

	/**
	 * Valida a formação dos campos.
	 * 
	 * @param torneio
	 *            Torneio sendo validado.
	 * @return Lista contendo mensagens de erro de validação.
	 */
	private List<Message> validarFormacaoDosCampos(Torneio torneio) {
		List<Message> msgs = new ArrayList<Message>();
		msgs.addAll(validarTamanho(torneio.getNome(), Constantes.LABELS.LABEL_NOME, null,
				Constantes.TAMANHOS.TAM_MAX_NOME));
		return msgs;
	}

	private List<Message> validarTamanho(String campo, String label, Integer min, Integer max) {
		List<Message> msgs = new ArrayList<Message>();
		int tamanhoValido = validadorGenerico.validarTamanho(campo, min, max);
		if (tamanhoValido == -1) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_MENOR_MINIMO, bundle.getString(label),
					min);
			msgs.add(msg);
		} else if (tamanhoValido == 1) {
			Message msg = mensagemUtil.buscaMensagem(MensagemAplicacaoErro.CAMPO_MAIOR_MAXIMO, bundle.getString(label),
					max);
			msgs.add(msg);
		}
		return msgs;
	}

	public void setBundle(ResourceBundle bundle) {
		this.bundle = bundle;
	}

	/**
	 * {@inheritDoc}
	 */
	public void setLogger(Logger logger) {
		this.logger = logger;
	}

	public void setMensagemUtil(MensagemUtil mensagemUtil) {
		this.mensagemUtil = mensagemUtil;
	}

	public void setValidadorGenerico(ValidadorGenerico validadorGenerico) {
		this.validadorGenerico = validadorGenerico;
	}

}
